﻿#include "mainwindow.h"
#include "ui_mainwindow.h"

#define WAIT_USB_RESP_TIME  200 
#define WAIT_USB_WR_TIME  	60000

int TimeStart = 2000;

void MainWindow::Port_Dlbox_Port_Init()
{
    Port_dlbox = new QSerialPort();
    Thread_dlbox = new QThread();
    connect(Thread_dlbox, &QThread::finished, this,&QObject::deleteLater);
    Thread_dlbox->start();
    Port_dlbox->moveToThread(Thread_dlbox);
    connect(Port_dlbox, &QSerialPort::readyRead, this, &MainWindow::Port_Dlbox_Read_Clicked);

    // dlbox
    SyncTimer_dlbox = new QTimer;
    connect(SyncTimer_dlbox,&QTimer::timeout,this,&MainWindow::Port_Dlbox_Sync_Timer);//同步
    SyncTimer_dlbox->stop();
    RecvTimer_dlbox = new QTimer;
    connect(RecvTimer_dlbox,&QTimer::timeout,this,&MainWindow::Port_Dlbox_Read_Data);//
    RecvTimer_dlbox->stop();
    WaitTimer_dlbox = new QTimer(this);
    connect(WaitTimer_dlbox,&QTimer::timeout,this,&MainWindow::Port_Dlbox_Once_Timer);
    WaitTimer_dlbox->setSingleShot(true);
}

// 连接命令
bool MainWindow::DlboxSerial_LinkCmd_Link()
{
	// 
	QByteArray CmdData;
	QByteArray CmdPage;
	CmdPage.clear();
	CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_LINK, CmdData));
	// 启动等待接收定时器
	return Wait_Time_to_Recv(CmdPage);
}

// 同步定时器,每5000ms定时发送同步命令
void MainWindow::Port_Dlbox_Sync_Timer()
{
	// 
	QByteArray CmdData;
	QByteArray CmdPage;
	CmdPage.clear();
	CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_SYNC, CmdData));
	// 启动等待接收定时器
	if(!Wait_Time_to_Recv(CmdPage))
	{
        //停止定时器
        SyncTimer_dlbox->stop();
        //断开连接
        LangureStr_Init_Btn_Unlink(ui->btn_link_dlbox);
        on_btn_link_dlbox_clicked();
	}
}

// 读盖板码命令
bool MainWindow::DlboxSerial_LinkCmd_ReadMtsn()
{
	// 
	QByteArray CmdData;
	QByteArray CmdPage;
	CmdPage.clear();
	CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_READ_MTSN, CmdData));
	// 启动等待接收定时器
	return Wait_Time_to_Recv(CmdPage);
}
// 写盖板码命令
bool MainWindow::DlboxSerial_LinkCmd_BurnMtsn(QByteArray CmdData)
{
    //
    QByteArray CmdPage;
    CmdPage.clear();
    CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_BURN_MTSN, CmdData));
    TimeStart = 60000;
    // 启动等待接收定时器
    return Wait_Time_to_Recv(CmdPage);
}
// 读数据命令
bool MainWindow::DlboxSerial_LinkCmd_ReadData()
{
    //
    QByteArray CmdData;
    QByteArray CmdPage;
    CmdPage.clear();
    CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_READ_DATA, CmdData));
    TimeStart = 10000;
    // 启动等待接收定时器
    return Wait_Time_to_Recv(CmdPage);
}
// 写数据命令
bool MainWindow::DlboxSerial_LinkCmd_BurnData(QByteArray CmdData)
{
    //
    QByteArray CmdPage;
    CmdPage.clear();
    CmdPage.append(Pc_To_Dlbox_Compose(USB_PAGE_BURN_DATA, CmdData));
    TimeStart = 2000;
    // 启动等待接收定时器
    return Wait_Time_to_Recv(CmdPage);
}

// 命令发送
QByteArray DlboxCmd_HEAD_Compose(uint8_t CmdStu, uint16_t DataSize)
{
    QByteArray CmdBuff;
    // Head
    CmdBuff.clear();
    CmdBuff.append(USB_PAGE_HEAD);
    // Cmd
    QByteArray CmdStr;
    CmdStr.clear();
    CmdStr.append(CmdStu);                  //code
    CmdStr.append((DataSize >> 0) & 0xFF);  //size.lsb
    CmdStr.append((DataSize >> 8) & 0xFF);  //size.msb
    CmdBuff.append("    ");
    CmdBuff[9] = myserial_EccCalc(CmdStr);
    CmdBuff[6] = CmdStr[0]; //code
    CmdBuff[7] = CmdStr[1]; //size.lsb
    CmdBuff[8] = CmdStr[2]; //size.msb
    return CmdBuff;
}
QByteArray DlboxCmd_CMD_Compose(uint8_t CmdStu, QByteArray DataBuff, uint16_t DataSize)
{
    QByteArray CmdBuff;
    // Head
    CmdBuff.clear();
    CmdBuff.append(DlboxCmd_HEAD_Compose(CmdStu, DataSize));

    // Data
    DataBuff.append(2, char(0));
    myserial_CmdCrc(DataBuff, DataSize);
    CmdBuff.append(DataBuff);

    return CmdBuff;
}
QByteArray MainWindow::Pc_To_Dlbox_Compose(uint8_t CmdStu, QByteArray CmdData)
{
	QByteArray CmdPage;
	CmdPage.clear();
	
    switch(CmdStu)
	{
		case USB_PAGE_LINK:
		case USB_PAGE_SYNC:
		case USB_PAGE_BREAK:
		case USB_PAGE_REPEAT:
		{
               CmdPage.append(DlboxCmd_HEAD_Compose(CmdStu, 0));
			break;
		}
		case USB_PAGE_BURN_MTSN:
        case USB_PAGE_READ_MTSN:
		{
			//
            CmdData.insert(0, (ModelStu_dlbox&0x000000FF));
			
            CmdPage.append(DlboxCmd_CMD_Compose(CmdStu, CmdData, CmdData.size()));
			break;
		}
        case USB_PAGE_BURN_DATA:
        case USB_PAGE_READ_DATA:
        {
            //
            CmdData.insert(0, (ModelStu_dlbox&0x000000FF));
            CmdData.insert(1, ((DataCnt_dlbox-1)&0x000000FF));

            CmdPage.append(DlboxCmd_CMD_Compose(CmdStu, CmdData, CmdData.size()));
            break;
        }
	}
	RespWait_dlbox = WAIT_USB_RESP_TIME;
    TimeStart = 2000;
	
	return CmdPage;
}
//在6s内循环等待 mcu 应答
bool MainWindow::Wait_Time_to_Recv(QByteArray CmdPage)
{
    int i = 0;
    TimeStart = 60000;
    do
    {
         // 发送包
         Port_dlbox->write(CmdPage);
         i++;
         // 等待设备回应
         RespStu_dlbox = USB_PAGE_NULL;
         WaitTimer_dlbox->start(TimeStart);
         while(USB_PAGE_NULL == RespStu_dlbox && ConnectStu_dlbox) QApplication::processEvents();
         WaitTimer_dlbox->stop();
         OutCnt_dlbox++;
        if(USB_PAGE_SYNC == RespStu_dlbox ||
           USB_PAGE_READ_MTSN == RespStu_dlbox ||
           USB_PAGE_READ_DATA == RespStu_dlbox ||
           USB_PAGE_BURN_MTSN == RespStu_dlbox ||
           USB_PAGE_BURN_DATA == RespStu_dlbox)
        {
            OutCnt_dlbox = 0;
        }
        if(OutCnt_dlbox == 6 || USB_PAGE_ERROR == RespStu_dlbox)
        {
            OutCnt_dlbox = 0;
            if(RespErrMsg_dlbox.mid(0,3) == USB_PAGE_ERR_FPC) // 型号不正确
            {
                if(LangureStu == 1)
                {
                    LangureStr = "The model does not match, please select the correct model or check the cable arrangement";
                }
                else
                {
                    LangureStr = "机型不符，请选择正确的型号或检查排线";
                }
                InsertText(ui->te_prin_dlbox, LangureStr, DLBOX_FONT_SIZE, APP_FONT_COLOR_FAILED);
                RespErrMsg_dlbox.clear();
            }
            return false;
        }
    }while(OutCnt_dlbox);
    return true;
}
//在60s/120s内循环等待 mcu 应答
bool MainWindow::Wait_TimeOut_to_Wait_Dlbox_Answer()
{
    int i = 0;
    TimeStart = 60000;
    do
    {
         i++;
         // 等待设备回应
         RespStu_dlbox = USB_PAGE_NULL;
         WaitTimer_dlbox->start(TimeStart);
         while(USB_PAGE_NULL == RespStu_dlbox && ConnectStu_dlbox) QApplication::processEvents();
         WaitTimer_dlbox->stop();
         OutCnt_dlbox++;
        if(USB_PAGE_SYNC == RespStu_dlbox ||
           USB_PAGE_READ_MTSN == RespStu_dlbox ||
           USB_PAGE_READ_DATA == RespStu_dlbox ||
           USB_PAGE_BURN_MTSN == RespStu_dlbox ||
           USB_PAGE_BURN_DATA == RespStu_dlbox)
        {
            OutCnt_dlbox = 0;
        }
        if(OutCnt_dlbox == 6 || USB_PAGE_ERROR == RespStu_dlbox)
        {
            OutCnt_dlbox = 0;
            if(RespErrMsg_dlbox.mid(0,3) == USB_PAGE_ERR_FPC) // 型号不正确
            {
                if(LangureStu == 1)
                {
                    LangureStr = "The model does not match, please select the correct model or check the cable arrangement";
                }
                else
                {
                    LangureStr = "机型不符，请选择正确的型号或检查排线";
                }
                InsertText(ui->te_prin_dlbox, LangureStr, DLBOX_FONT_SIZE, APP_FONT_COLOR_FAILED);
                RespErrMsg_dlbox.clear();
            }
            return false;
        }
    }while(OutCnt_dlbox);
    return true;
}

// 数据接收
void MainWindow::Port_Dlbox_Read_Clicked()
{
    if(!RecvTimer_dlbox->isActive())
    {
        RecvTimer_dlbox->start(200);
    }
}
void MainWindow::Port_Dlbox_Read_Data()
{
    RecvTimer_dlbox->stop();

    QByteArray ReadBuff;
    //从接收缓冲区中读取数据
    ReadBuff = Port_dlbox->readAll();
    RecvStr_dlbox.append(ReadBuff);
    //若接收的命令前有乱码，则截取后面的命令
    if(0 < RecvStr_dlbox.indexOf(USB_PAGE_HEAD))
    {
        RecvStr_dlbox = RecvStr_dlbox.mid(RecvStr_dlbox.indexOf(USB_PAGE_HEAD), RecvStr_dlbox.size()-RecvStr_dlbox.indexOf(USB_PAGE_HEAD));
    }
    qDebug()<<RecvStr_dlbox;
    if(0 == RecvStr_dlbox.indexOf(USB_PAGE_HEAD))
    {
        if(myserial_Cmd_Check(RecvStr_dlbox))
        {
            int DataSize = RecvStr_dlbox.size()-10;
            //判断命令类型
            uint8_t CmdStu = RecvStr_dlbox[6];
            switch(CmdStu)
            {
                case USB_PAGE_SYNC:
                {
                    RespStu_dlbox = USB_PAGE_SYNC;
                    RespSN_dlbox = RecvStr_dlbox.mid(10, 12);
                    RespVers_dlbox = RecvStr_dlbox.mid(22, 8);
                    break;
                }
                case USB_PAGE_REPEAT:       RespStu_dlbox = USB_PAGE_REPEAT;      break;
                case USB_PAGE_BUSY:         RespStu_dlbox = USB_PAGE_BUSY;        break;
                case USB_PAGE_ERROR:
                {
                    RespStu_dlbox = USB_PAGE_ERROR;
                    RespErrMsg_dlbox = RecvStr_dlbox.mid(10, DataSize);
                    break;
                }
                case USB_PAGE_READ_MTSN:
                {
                    RespMtsn_dlbox = RecvStr_dlbox.mid(10, DataSize);
                    if(RespMtsn_dlbox.size() < 44)
                    {
                        RespStu_dlbox = USB_PAGE_BUSY;
                    }
                    else
                    {
                        RespStu_dlbox = USB_PAGE_READ_MTSN;
                    }
                    break;
                }
                case USB_PAGE_READ_DATA:
                {
                    RespStu_dlbox = USB_PAGE_READ_DATA;
                    RespData_dlbox = RecvStr_dlbox.mid(10, DataSize);
                    break;
                }
                case USB_PAGE_BURN_MTSN:    RespStu_dlbox = USB_PAGE_BURN_MTSN;   break;
                case USB_PAGE_BURN_DATA:    RespStu_dlbox = USB_PAGE_BURN_DATA;   break;
                default:                    RespStu_dlbox = USB_PAGE_BREAK;       break;
            }
            RecvStr_dlbox.clear();
        }
        else
        {
            RecvStr_dlbox.clear();
        }
    }
}

// 串口初始化函数
bool MainWindow::InitSerial_Dlbox(QSerialPort *PortSerial, QString portname)
{
    // 设置端口部分参数
    PortSerial->setBaudRate(QSerialPort::Baud115200);
    PortSerial->setDataBits(QSerialPort::Data8);
    PortSerial->setParity(QSerialPort::NoParity);
    PortSerial->setStopBits(QSerialPort::OneStop);
    PortSerial->setPortName(portname);
    if(!PortSerial->open(QIODevice::ReadWrite))
    {
        qDebug()<<"Serial port opening failed";
        return false;
    }
    qDebug()<<"Serial port open successfully";

    return true;
}
